package com.tianhe.common.tongsuo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

@Component
@Slf4j
public class SM2JNI {

//    private final SM2JNI sm2 = new SM2JNI();

    static {
        // 先加载依赖库
        //获取操作系统类型
        String osName = System.getProperties().getProperty("os.name").toLowerCase();
        if (osName != null && osName.startsWith("linux")) {
            System.load("/home/gm/lib/libgmjni.so");
        } else if (osName != null && osName.startsWith("windows")) {
            String loadLibrary = System.getProperty("user.dir")  + File.separator+ "sm" + File.separator+"gm"+File.separator+"lib"+File.separator;
            String library = "libgmjni.dll";
            System.out.println(loadLibrary+library);
            System.load(System.getProperty("user.dir") + File.separator+"sm"+ File.separator+"tongsuo"+ File.separator+"bin"+ File.separator+"libcrypto-3-x64.dll");
            System.load(System.getProperty("user.dir") + File.separator+"sm"+ File.separator+"tongsuo"+ File.separator+"bin"+ File.separator+"libssl-3-x64.dll");
            System.load(System.getProperty("user.dir") + File.separator+"sm"+ File.separator+"gm"+ File.separator+"lib"+ File.separator+"libgmjni.dll");
        } else {
            log.info("其他操作系统");
        }
    }

    public native int generateKeyPair(String[] keyPairOut);
    public native int encrypt(String pemPublicKey, byte[] id, byte[] plaintext, byte[] ciphertext);
    public native int decrypt(String pemPrivateKey, byte[] id, byte[] ciphertext, byte[] plaintext);
    public native int sign(String pemPrivateKey, byte[] id, byte[] msg, byte[] signOut);
    public native int verify(String pemPublicKey, byte[] id, byte[] msg, byte[] signature, int signLen);

    /**
     * 生成SM2密钥对
     * @return 数组，[0]是私钥，[1]是公钥
     */
    public String[] generateKeyPair() {
        SM2JNI sm2 = new SM2JNI();
        String[] keyPair = new String[2];
        if (sm2.generateKeyPair(keyPair) != 0) {
            throw new RuntimeException("Failed to generate SM2 key pair");
        }
        return keyPair;
    }

    /**
     * SM2加密
     * @param publicKey 公钥
     * @param id 用户ID
     * @param plaintext 明文
     * @return 加密后的十六进制字符串
     */
    public String encrypt(String publicKey, String id, String plaintext) {
        SM2JNI sm2 = new SM2JNI();
        byte[] idBytes = id.getBytes(StandardCharsets.UTF_8);
        byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_8);

        byte[] ciphertext = new byte[256]; // 预留足够空间
        int cipherLen = sm2.encrypt(publicKey, idBytes, plaintextBytes, ciphertext);

        if (cipherLen <= 0) {
            throw new RuntimeException("SM2 encrypt failed");
        }

        byte[] realCipher = Arrays.copyOf(ciphertext, cipherLen);
        return bytesToHex(realCipher);
    }

    /**
     * SM2解密
     * @param privateKey 私钥
     * @param id 用户ID
     * @param ciphertextHex 加密后的十六进制字符串
     * @return 解密后的原始字符串
     */
    public String decrypt(String privateKey, String id, String ciphertextHex) {
        SM2JNI sm2 = new SM2JNI();
        byte[] idBytes = id.getBytes(StandardCharsets.UTF_8);
        byte[] ciphertext = hexToBytes(ciphertextHex);

        byte[] decrypted = new byte[256]; // 预留足够空间
        int plainLen = sm2.decrypt(privateKey, idBytes, ciphertext, decrypted);

        if (plainLen <= 0) {
            throw new RuntimeException("SM2 decrypt failed");
        }

        return new String(decrypted, 0, plainLen, StandardCharsets.UTF_8);
    }

    /**
     * 字节数组转十六进制字符串
     */
    private String bytesToHex(byte[] data) {
        StringBuilder sb = new StringBuilder();
        for (byte b : data) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }

    /**
     * 十六进制字符串转字节数组
     */
    private byte[] hexToBytes(String hex) {
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i+1), 16));
        }
        return data;
    }

//    public static void main(String[] args) {
//        SM2JNI sm2 = new SM2JNI();
//
//        /* 1. [0] = private key, [1] = public key */
//        String[] keyPair = new String[2];
//        if (sm2.generateKeyPair(keyPair) != 0) {
//            System.err.println("Failed to generate SM2 key pair.");
//            return;
//        }
//
//        String privateKey = keyPair[0];
//        String publicKey = keyPair[1];
//        System.out.println("=== SM2 Private Key ===");
//        System.out.println(privateKey);
//        System.out.println("=== SM2 Public Key ===");
//        System.out.println(publicKey);
//
//        String idStr = "1234567812345678";
//        byte[] id = idStr.getBytes(StandardCharsets.UTF_8);
//        String plaintextStr = "Hello, SM2!";
//        byte[] plaintext = plaintextStr.getBytes(StandardCharsets.UTF_8);
//
//        // 3. 加密，留足够空间
//        byte[] ciphertext = new byte[256];
//        int cipherLen = sm2.encrypt(publicKey, id, plaintext, ciphertext);
//        if (cipherLen <= 0) {
//            System.err.println("SM2 encrypt failed.");
//            return;
//        }
//        byte[] realCipher = Arrays.copyOf(ciphertext, cipherLen);
//        System.out.println("SM2 ciphertext: " + bytesToHex(realCipher));
//
//        // 4. 解密
//        byte[] decrypted = new byte[plaintext.length];
//        int plainLen = sm2.decrypt(privateKey, id, realCipher, decrypted);
//        if (plainLen <= 0) {
//            System.err.println("SM2 decrypt failed.");
//            return;
//        }
//        String decryptedStr = new String(decrypted, 0, plainLen, StandardCharsets.UTF_8);
//        System.out.println("SM2 plaintext: " + decryptedStr);
//
//        // 5. 签名，留足够空间
//        byte[] signature = new byte[128];
//        int signLen = sm2.sign(privateKey, id, plaintext, signature);
//        if (signLen <= 0) {
//            System.err.println("SM2 sign failed.");
//            return;
//        }
//        byte[] realSign = Arrays.copyOf(signature, signLen);
//        System.out.println("SM2 signature: " + bytesToHex(realSign));
//
//        // 6. 验签
//        int verifyResult = sm2.verify(publicKey, id, plaintext, realSign, signLen);
//        System.out.println("SM2 Verify Result: " + (verifyResult == 1 ? "Success" : "Failed"));
//    }
//
//    private static String bytesToHex(byte[] data) {
//        StringBuilder sb = new StringBuilder();
//        for (byte b : data) {
//            sb.append(String.format("%02X", b));
//        }
//        return sb.toString();
//    }
}